import { _decorator, AudioClip, AudioSource, Component, Node, sys } from 'cc';
import { DEBUG, PREVIEW } from 'cc/env';

import AudioExt from '../base/AudioExt';
import AudioSetting, {
    EVENT_KEY_SOUND_SETTING, IAudioSet, TAudioStatus
} from '../base/AudioSetting';
import BundleExt from '../base/BundleExt';
import EventExt from '../base/EventExt';
import EventHelper from '../base/EventHelper';
import { IEventAudio } from '../base/EventType';

const { ccclass, property } = _decorator;

/**
 * Cocos Creator 音效播放功能拓展组件
 * 采用监听事件机制--EVENT_KEY_PLAY_AUDIO
 * 支持挂载多个音效控制组件
 */
@ccclass("AudioComponent")
export default class AudioComponent extends Component {

    // 游戏背景音乐(有且仅有一条)
    @property(AudioSource)
    protected readonly audioBGM: AudioSource = null;

    // 音效加载形式
    @property
    private readonly loadDir: boolean = false;

    // 音效列表--直接手动绑定指定音效
    @property({
        type: [AudioClip],
        visible() {
            return !this.loadDir;
        }
    })
    private audios: AudioClip[] = [];

    // 加载音效目录(默认“resources”)
    @property({
        tooltip: "音效资源所在Bundle包名称，默认cocos内置的resources包",
        visible() {
            return this.loadDir;
        }
    })
    private readonly bundleName: string = "resources";

    // 包内音效目录相对路径
    @property({
        tooltip: "音效资源文件夹，在包内的相对路径；以符号'/'分割文件夹名，不支持'./'、'../'形式",
        visible() {
            return this.loadDir;
        }
    })
    private readonly audioDir: string = '';

    /** 音效文件列表 */
    private static _audioList: Map<string, AudioClip> = null;
    /** 更新音效列表（允许UI挂载多个组件） */
    private updateAudioList(audios: AudioClip[]) {
        if (!AudioComponent._audioList)
            AudioComponent._audioList = new Map();

        if (!!audios && audios.length > 0)
            audios.forEach(clip => {
                if (!!clip && clip.isValid) {
                    AudioComponent._audioList.set(clip.name, clip);
                    DEBUG && console.debug("[AudioComponent] 加载音效资源: ", clip.name);
                }
            });
    }
    /**
     * 获取指定音效
     * @param audioName 音效名称
     * @returns 
     */
    private getClip(audioName: string): AudioClip {
        const clip: AudioClip = AudioComponent._audioList.get(audioName);
        DEBUG && !clip && console.debug("【AudioComp】未查询到指定音效文件：", audioName);
        return clip;
    }


    protected onLoad(): void {
        // 监听自定义事件
        EventExt.on(EVENT_KEY_SOUND_SETTING, (p: IAudioSet) => {
            if ((p.type & TAudioStatus.Mute) != 0 || (p.type & TAudioStatus.BGM) != 0)
                this.checkAndUpdateBGM();
        }, this);
        EventHelper.onAudio((param: IEventAudio): boolean => {
            // 播放音效
            PREVIEW && console.log("[AudioComponent] 监听音效自定义事件:", JSON.stringify(param));
            if (!param || param.audioName.length == 0)
                return true;

            if (!!param.isBGM) {
                this.changeBGM(param.audioName);
                return !!this.audioBGM;
            }
            else if (!!param.isVoice) {
                this.playAudio(param.audioName);
                return true;
            }
            else {
                this.playVoice(param.audioName);
                return true;
            }
        }, this);

        // web平台特殊处理
        if (!!this.audioBGM && sys.isBrowser)
            this.node.once(Node.EventType.TOUCH_START, () => {
                this.audioBGM.pause();
                this.checkAndUpdateBGM();
            });
    }

    protected onDestroy(): void {
        EventExt.targetOff(this);
    }

    start() {
        this.checkAndUpdateBGM();
        if (this.loadDir)
            this.loadAudioDir();
        else
            this.updateAudioList(this.audios);
    }

    /** 加载音效文件夹 */
    private loadAudioDir() {
        if (!this.audioDir || !this.audioDir.length)
            return;
        BundleExt.loadDir(this.audioDir, AudioClip, (err: Error | null, data: AudioClip[]) => {
            if (err) {
                DEBUG && console.error("[AudioComponent] ", err.name, ": ", err.message);
            }
            else if (this && this.isValid) {
                this.updateAudioList(data);
            }
        }, this.bundleName);
    }

    /** 播放音效 */
    protected playAudio(audioName: string) {
        if (!AudioSetting.sound)
            return;
        const audio: AudioClip = this.getClip(audioName);
        AudioExt.playAudioClip(audio, true, false, this);
    }

    /** 播放人物语音 */
    protected playVoice(audioName: string) {
        if (!AudioSetting.voice)
            return;
        const audio: AudioClip = this.getClip(audioName);
        AudioExt.playAudioClip(audio, true, false, this);
    }

    /** 更换播放背景音乐 */
    protected changeBGM(audioName: string) {
        if (!this.audioBGM || this.audioBGM.clip.name == audioName)
            return;
        const audio: AudioClip = this.getClip(audioName);
        if (!audio || !audio.isValid) return;
        this.audioBGM.stop();
        this.audioBGM.clip = audio;
        this.checkAndUpdateBGM();
    }

    /** 检测并更新背景音乐状态 */
    protected checkAndUpdateBGM() {
        if (!this.audioBGM)
            return;
        if (AudioSetting.BGM)
            this.audioBGM.play();
        else
            this.audioBGM.pause();
    }

}
